package main;

import java.rmi.AccessException;
import java.rmi.NotBoundException;
import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;

import registry.RemoteRegistry;
import tools.CheckArgument;
import model.Entry;
import model.HostPort;
import node.RemoteNode;
import node.RemoteNodeRMIEndpoint;

/**
 * @author Matt Adams
 * @author James Marquardt
 * @author Justin Wong
 */
public class ConcurrentOperationTest implements Runnable {
    
    private static String NAME_IN_REGISTRY = RemoteNodeRMIEndpoint.NAME_IN_REGISTRY;
    
    private final RemoteRegistry registryStub;
    
    private final String[] operations;
    
    
    public ConcurrentOperationTest(final RemoteRegistry registryStub, final String[] operations) {
        this.registryStub = registryStub;
        this.operations = operations;
    }
  
    /**
     * @param hostPortRegistryArgs
     */
    public static void main(String[] hostPortRegistryArgs) {
        if (hostPortRegistryArgs.length != 3) {
            System.out.println("Usage: <registry hostname> <registry port> <registry name>");
            System.exit(1);
        }
        final String registryHost = hostPortRegistryArgs[0];
        final int registryPort = CheckArgument.getValidPortFromString((hostPortRegistryArgs[1]));
        final String registryName = hostPortRegistryArgs[2];
        RemoteRegistry registryStub = null;
        try {
            Registry registry = LocateRegistry.getRegistry(registryHost, registryPort);
            registryStub = (RemoteRegistry) registry.lookup(registryName);
        } catch(RemoteException e) {
            System.out.println("Unable to locate registry.");
            System.exit(1);
        } catch (NotBoundException e) {
            System.out.println("Unable to locate registry.");
            System.exit(1);
        }
        
        //Test operations one
        final String[] operationsOne = {"put", "1", "HELLO", "put", "1", "SIR", "put", "1", "HOW", "put", "4", "are", "put", "5", "you?"};
        final String[] operationsTwo = {"put", "6", "I'm", "put", "7", "fine", "put", "8", "thank", "put", "9", "for", "put", "10", "asking."};
        final String[] operationsThree = {"put", "never", "going","put", "to", "give","put", "you", "up","put","make", "you"};
        
        final ConcurrentOperationTest conTestOne = new ConcurrentOperationTest(registryStub, operationsOne);
        final ConcurrentOperationTest conTestTwo = new ConcurrentOperationTest(registryStub, operationsTwo);
        final ConcurrentOperationTest conTestThree = new ConcurrentOperationTest(registryStub, operationsThree);
        
        Thread one = new Thread(conTestOne);
        Thread two = new Thread(conTestTwo);
        Thread three= new Thread(conTestThree);
        
        one.start();
        two.start();
        three.start();
    }
        

    @Override
    public void run() {
        // TODO Auto-generated method stub
        int i = 0;
        while(true) {
        	int node_id=0;
        	RemoteNode stub2 = null;
    		try {
    			node_id = registryStub.getArbitraryNode();
    			System.out.println("arbitrary node id: " + node_id );
    		} catch (RemoteException e1) {
    			System.out.println("Error getting node.");
    			return;
    		}
    		
    		HostPort loc = null;
    		
    		try {
    			loc = registryStub.getNodeHostPort(node_id);
    			if(loc == null) {
    				System.out.println("Node " + node_id + " has not been registered.");
    				return;
    			}
    		} catch (RemoteException e) {
    			System.out.println("Error calling remote method");
    			return;
    		}
    		
            try {
            	Registry registry2 = LocateRegistry.getRegistry(loc.getHost(), loc.getPort());
                stub2 = (RemoteNode) registry2.lookup(NAME_IN_REGISTRY + loc.toString());
                
            } catch (NotBoundException e) {
                e.printStackTrace();
            } catch (AccessException e) {
            	System.out.println("Could not access node " + node_id);
    		} catch (RemoteException e) {
    			System.out.println("Could not locate node " +  node_id);
    			e.printStackTrace();
    		}
        	
        	if(i >= operations.length) {
        		break;
        	} else if(operations[i].equals("put")) {
        		int key = operations[i+1].hashCode();
        		String value = operations[i+2];
        		Entry ent = new Entry(key, value);
        		try {
					stub2.insertEntry(ent);
				} catch (RemoteException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
        		i+=3;
        	}
        }
    }

}
